package com.youdoneed.user.role;

import com.querydsl.sql.SQLQueryFactory;
import com.querydsl.sql.dml.SQLInsertClause;
import com.youdoneed.base.application.AppException;
import com.youdoneed.base.common.GlobalIdWorker;
import com.youdoneed.user.model.Authority;
import com.youdoneed.user.model.Role;
import com.youdoneed.user.model.RoleAuthority;
import com.youdoneed.user.query.QAdminRole;
import com.youdoneed.user.query.QAuthority;
import com.youdoneed.user.query.QRole;
import com.youdoneed.user.query.QRoleAuthority;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * 角色管理服务实现类
 *
 * @author Ewing
 * @date 2017.2.8
 */
@Service
@Transactional
public class RoleServiceImpl implements RoleService {
    private final Logger logger = LoggerFactory.getLogger(RoleServiceImpl.class);

    @Autowired
    private SQLQueryFactory queryFactory;
    // 约定查询对象以大写开头
    private QAdminRole qAdminRole = QAdminRole.AdminRole;
    private QRole qRole = QRole.Role;
    private QRoleAuthority qRoleAuthority = QRoleAuthority.RoleAuthority;
    private QAuthority qAuthority = QAuthority.Authority;

    /**
     * 添加角色与权限关联。
     */
    private void addRoleAuthorities(String[] authorityIds, Role role) {
        // 添加角色与权限的关系
        if (authorityIds != null && authorityIds.length > 0) {
            // 保存权限与角色的关联关系
            SQLInsertClause insertClause = queryFactory.insert(qRoleAuthority);
            for (String authorityId : authorityIds) {
                Authority authority = queryFactory.selectFrom(qAuthority)
                        .where(qAuthority.authorityId.eq(authorityId))
                        .fetchOne();
                if (null == authority) {
                    continue;
                }
                RoleAuthority roleAuthority = new RoleAuthority();
                roleAuthority.setAuthorityId(authorityId);
                roleAuthority.setRoleId(role.getRoleId());
                roleAuthority.setCreateTime(new Date());
                insertClause.populate(roleAuthority)
                        .addBatch();
            }
            if (!insertClause.isEmpty()) {
                insertClause.execute();
            }
        }
    }

    @Override
    public Role findByRoleId(String roleId) {
        if (!StringUtils.hasText(roleId)) {
            throw new AppException("角色ID不能为空！");
        }
        return queryFactory.selectFrom(qRole)
                .where(qRole.roleId.eq(roleId))
                .fetchOne();
    }

    @Override
    public List<Role> findByName(String name) {
        if (!StringUtils.hasText(name)) {
            throw new AppException("角色名称不能为空！");
        }
        return queryFactory.selectFrom(qRole)
                .where(qRole.name.contains(name))
                .fetch();
    }

    @Override
    public List<Role> getAllRole() {
        return queryFactory.selectFrom(qRole)
                .fetch();
    }

    @Override
    public Role addRole(String name, String description, String[] authorityIds) {
        if (!StringUtils.hasText(name)) {
            throw new AppException("角色名称不能为空！");
        }

        // 防止重复添加角色
        if (queryFactory.selectFrom(qRole)
                .where(qRole.name.eq(name))
                .fetchCount() > 0) {
            throw new AppException("该角色名称已存在！");
        }

        // 添加角色
        Role role = new Role();
        role.setRoleId(GlobalIdWorker.nextString());
        role.setName(name);
        role.setDescription(description);
        role.setCreateTime(new Date());
        queryFactory.insert(qRole)
                .populate(role)
                .execute();

        // 添加角色与权限的关系
        addRoleAuthorities(authorityIds, role);
        return role;
    }

    @Override
    public void deleteRole(String roleId) {
        if (!StringUtils.hasText(roleId)) {
            throw new AppException("请选择一个角色。");
        }

        Role role = findByRoleId(roleId);
        if (null == role) {
            throw new AppException("该角色不存在或已被删除！");
        }

        // 删除管理员角色关系
        queryFactory.delete(qAdminRole)
                .where(qAdminRole.roleId.eq(roleId))
                .execute();

        // 删除角色权限关联
        queryFactory.delete(qRoleAuthority)
                .where(qRoleAuthority.roleId.eq(roleId))
                .execute();

        // 最后删除角色
        queryFactory.delete(qRole)
                .where(qRole.roleId.eq(roleId))
                .execute();
    }

    @Override
    @Transactional
    public Role updateRole(String roleId, String name, String description, String[] authorityIds) {
        if (!StringUtils.hasText(roleId)) {
            throw new AppException("角色ID不能为空！");
        }

        // 添加角色
        Role oldRole = findByRoleId(roleId);
        if (StringUtils.hasText(name) && !name.equals(oldRole.getName())) {
            // 防止重复角色
            if (queryFactory.selectFrom(qRole)
                    .where(qRole.name.eq(name))
                    .fetchCount() > 0) {
                throw new AppException("该角色名称已存在！");
            }
            oldRole.setName(name);
        }
        oldRole.setDescription(description);

        queryFactory.update(qRole)
                .populate(oldRole)
                .where(qRole.roleId.eq(roleId))
                .execute();

        // 删除角色权限关联
        queryFactory.delete(qRoleAuthority)
                .where(qRoleAuthority.roleId.eq(roleId))
                .execute();

        // 关联新的权限
        addRoleAuthorities(authorityIds, oldRole);
        return oldRole;
    }

    @Override
    public List<Authority> getRoleAllAuthority(String roleId) {
        if (!StringUtils.hasText(roleId)) {
            throw new AppException("角色ID不能为空！");
        }
        return queryFactory.selectFrom(qAuthority)
                .join(qRoleAuthority)
                .on(qAuthority.authorityId.eq(qRoleAuthority.authorityId))
                .where(qRoleAuthority.roleId.eq(roleId))
                .fetch();
    }

}
